package com.example.sc.learn.controller;

import com.example.sc.learn.domain.BingRoomTopThreeUser;
import com.example.sc.learn.domain.BiningRoomEatCountVO;
import com.example.sc.learn.entity.BiningRoom;
import com.example.sc.learn.entity.EatRecord;
import com.example.sc.learn.entity.User;
import com.example.sc.learn.service.BiningBusinessService;
import com.example.sc.learn.util.ResponseData;
import com.google.common.collect.Lists;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;


@Slf4j
@RequestMapping(value = "business")
@RestController
@Api(value = "业务接口",  description = "业务接口描述")
public class BusinessAPI {


    @Autowired
    private BiningBusinessService service;

//    业务需求：
//	1.用户的增加和查询
//	3.餐厅的增加和查询
//	5.添加用餐记录
//	6.查询每个餐厅的用餐累计人数和平均评价
//	7.查询每个餐厅的前三常用顾客
//	8.查询每个餐厅的评价星级
//	9.查询最喜欢下馆子的top5

    @ApiOperation(value = "业务1：新增用户信息", notes = "通过远程调用")
    @PostMapping("user")
    public ResponseData<Boolean> insertUser(@RequestBody User user){
        try {
            service.insertUser(user);
            return new ResponseData<>(true);
        }catch (Exception e){
            log.error("business insert user runtime exception", e);
        }
        log.info("business insert user success");
        return new ResponseData<>(false);
    }



    @ApiOperation(value = "业务2：根据用户编号获取用户信息", notes = "通过远程调用")
    @ApiImplicitParam(name = "userCode",  value = "用户编号",  paramType = "path", required = true)
    @GetMapping("user/{userCode}")
    public ResponseData<User> selectUserByUserCode(@PathVariable("userCode") String userCode){
        User user = null;
        try {
            user = service.selectByUserCode(userCode);
        }catch (Exception e){
            log.error("business find user runtime exception", e);
        }
        log.info("business find user result: {}", user);
        return new ResponseData<>(user);
    }


    @ApiOperation(value = "业务3：新增餐厅信息", notes = "通过本地调用")
    @PostMapping("bining_room")
    public ResponseData<Boolean> insertBiningRoom(@RequestBody BiningRoom biningRoom){
        try {
            service.insertBinBingRoom(biningRoom);
            return new ResponseData<>(true);
        }catch (Exception e){
            log.error("business insert biningRoom runtime exception", e);
        }
        log.info("business insert biningRoom success");
        return new ResponseData<>(false);
    }



    @ApiOperation(value = "业务4：根据餐厅编号获取餐厅信息", notes = "通过本地调用")
    @ApiImplicitParam(name = "biningCode",  value = "餐厅",  paramType = "path", required = true)
    @GetMapping("bining_room/{biningCode}")
    public ResponseData<BiningRoom> selectBiningRoomByUserCode(@PathVariable("biningCode") String biningCode){
        BiningRoom biningRoom = null;
        try {
            biningRoom = service.selectBiningRoomByCode(biningCode);
        }catch (Exception e){
            log.error("business find biningRoom runtime exception", e);
        }
        log.info("business find biningRoom result: {}", biningRoom);
        return new ResponseData<>(biningRoom);
    }



    @ApiOperation(value = "业务5：添加用餐记录", notes = "通过远程+本地调用")
    @ApiImplicitParams(value = {
            @ApiImplicitParam(name = "userCode",  value = "用户编号",  paramType = "query", required = true),
            @ApiImplicitParam(name = "biningCode",  value = "餐厅编号",  paramType = "query", required = true),
            @ApiImplicitParam(name = "valuation",  value = "评分等级【1-5】",  paramType = "query", dataType = "int", required = true)
    })
    @PostMapping("eat_record")
    public ResponseData<Boolean> selectBiningRoomByUserCode(@RequestParam("userCode") String userCode,
                                                            @RequestParam("biningCode") String biningCode,
                                                            @RequestParam("valuation") Integer valuation){
        if (valuation<1 || valuation>5){
            return new ResponseData<>("评分等级参数超出范围", false);
        }
        try {
            //检查用户合法性
            User user = service.selectByUserCode(userCode);
            if (user==null || Objects.isNull(user.getId())){
                return new ResponseData<>("用户不合法，请检查 ", false);
            }

            //检查餐厅合法性
            BiningRoom biningRoom = service.selectBiningRoomByCode(biningCode);
            if (biningRoom==null || Objects.isNull(biningRoom.getId())){
                return new ResponseData<>("餐厅不合法，请检查 ", false);
            }

            EatRecord eatRecord =  new EatRecord();
            eatRecord.setUserCode(userCode);
            eatRecord.setBiningRoomCode(biningCode);
            eatRecord.setCreateTime(new Date());
            eatRecord.setValuation(valuation);
            service.insertEatRecord(eatRecord);
            return new ResponseData<>(true);
        }catch (Exception e){
            log.error("business insert eatRecord runtime exception", e);
        }
        log.info("business insert eatRecord success");
        return new ResponseData<>(false);
    }



    @ApiOperation(value = "业务6：询每个餐厅的用餐累计人数和平均评价", notes = "通过远程+本地调用")
    @GetMapping("bining_room/eat_number")
    public ResponseData<ArrayList<BiningRoomEatCountVO>> selectBiningRoomEatNumber(){
        ArrayList<BiningRoomEatCountVO> vos = Lists.newArrayList();
        try {
            //查询所用餐厅
            List<BiningRoom> rooms = service.selectAllBiningRoom();
            if (!CollectionUtils.isEmpty(rooms)){
                rooms.forEach(r -> {
                    BiningRoomEatCountVO vo = new BiningRoomEatCountVO();
                    //根据每个餐厅查询所有用餐记录
                    List<EatRecord> eats = service.selectEatRecordByBiningCode(r.getBiningRoomCode());
                    int totalEat = 0;
                    BigDecimal avgPoint = BigDecimal.ZERO;
                    if (!CollectionUtils.isEmpty(eats)){
                        totalEat = eats.size();
                        Double avgVal = eats.stream()
                                .collect(Collectors.averagingDouble(EatRecord::getValuation));
                        avgPoint = new BigDecimal(avgVal);
                    }
                    vo.setBiningRoomCode(r.getBiningRoomCode());
                    vo.setBiningRoomName(r.getBiningRoomName());
                    vo.setTotalNumber(totalEat);
                    vo.setAvgPoint(avgPoint);
                    vos.add(vo);
                });
            }
        }catch (Exception e){
            log.error("business insert eatRecord runtime exception", e);
        }
        log.info("business insert eatRecord success");
        return new ResponseData<>(vos);
    }

    @ApiOperation(value = "业务7：查询每个餐厅的前三常用顾客")
    @GetMapping("bining_room/selectTopThreeUser")
    /**
     * q1:
     * url路由中的命名规范是
     * 1、不能有动词
     * 2、不能有大写
     */
    public ResponseData<ArrayList<BingRoomTopThreeUser>> selectTopThreeUser(){
        ArrayList<BingRoomTopThreeUser> list  =  Lists.newArrayList();
        //查看有多少餐厅
        List<BiningRoom> rooms = service.selectAllBiningRoom();
        //q2:日志不要用：System.out.print  用log4j 或者  slf4j  本框架用的是slf4j  其他业务就是用的log
        System.out.println(rooms.size());
        //q3:循环之前得用CollectionUtils.isEmpty判断空
        for (BiningRoom li: rooms) {
            //查找每个餐厅前三的用户
            BingRoomTopThreeUser bingRoomTopThreeUser = new BingRoomTopThreeUser();
            bingRoomTopThreeUser.setBiningRoomCode(li.getBiningRoomCode());
            bingRoomTopThreeUser.setBiningRoomName(li.getBiningRoomName());
            //q4:这个赋值是多余的。idea都给出波浪线警告了，赋值后下面又再次赋值了
            List<User> list1 = Lists.newArrayList();
            //q5:top几是不确定的，所以这个方法应该是写一个分页查询，根据传参（传入第几页每页几个，
            // 当前业务就传当前页为1， 每页数目为3）,不应该单独写一个top three
            list1 = service.selectTopThreeUser(li.getBiningRoomCode());
            bingRoomTopThreeUser.setUserList(list1);
            list.add(bingRoomTopThreeUser);
        }

        //q6:加入异常判断   防止用户使用时报错


        //还有一种偷懒的方法，查出所有用餐记录，然后使用stream排序分组（优点实现快，代码简洁）

        //用基本lambda排序list
        List<BingRoomTopThreeUser> users = list.stream()
                .sorted(new Comparator<BingRoomTopThreeUser>() {
                    @Override
                    public int compare(BingRoomTopThreeUser o1, BingRoomTopThreeUser o2) {
                        return o1.getBiningRoomCode().compareTo(o2.getBiningRoomCode());
                    }
                })
                .collect(Collectors.toList());


        //用方法引用的lambda排序list
        /**
         * 看得到吗？
         * 嗯
         * 上面就是基本的lambda，还可以使用方法引用变得更简洁，使用idea提示操作就可以
         * 不用死记忆
         * 看吧；idea的快捷提示；  Alt + Enter
         * 是不是很6666？
         * 和AndroidStudio一样的额   用过
         * 方法引用就是简洁版的lambda表达式，你看过视频就会用了。OK？
         * 好的哦
         * 去忙吧你
         * ok 888
         */
        List<BingRoomTopThreeUser> users2 = list.stream()
                .sorted(Comparator.comparing(BingRoomTopThreeUser::getBiningRoomCode))
                .collect(Collectors.toList());


        return new ResponseData<>(list);
    }



}
